﻿using System;
using System.Linq;
using System.Threading.Tasks;
using DailyPoetryX.Models;
using DailyPoetryX.Services;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using MvvmHelpers;

namespace DailyPoetryX.ViewModels {
    public class FavoritePageViewModel : ViewModelBase {
        /******** 构造函数 ********/

        private IFavoriteStorage favoriteStorage;
        private IPoetryStorage poetryStorage;
        IContentNavigationService contentNavigationService;

        public FavoritePageViewModel(IFavoriteStorage favoriteStorage,
            IPoetryStorage poetryStorage,
            IContentNavigationService contentNavigationService) {
            this.favoriteStorage = favoriteStorage;
            this.poetryStorage = poetryStorage;
            this.contentNavigationService = contentNavigationService;

            favoriteStorage.Updated += FavoriteStorageOnUpdated;
        }

        /******** 绑定属性 ********/

        public ObservableRangeCollection<PoetryFavorite> PoetryFavorites {
            get;
        } = new ObservableRangeCollection<PoetryFavorite>();

        public bool Loading {
            get => _loading;
            set => Set(nameof(Loading), ref _loading, value);
        }

        private bool _loading;

        /******** 绑定命令 ********/

        public RelayCommand PageAppearingCommand =>
            _pageAppearingCommand ?? (_pageAppearingCommand = new RelayCommand(
                async () => {
                    var run = false;

                    if (!pageLoaded) {
                        lock (pageLoadedLock) {
                            if (!pageLoaded) {
                                pageLoaded = true;
                                run = true;
                            }
                        }
                    }

                    if (!run) return;

                    Loading = true;
                    PoetryFavorites.Clear();
                    var favoriteList =
                        await favoriteStorage.GetFavoritesAsync();

                    PoetryFavorites.AddRange((await Task.WhenAll(
                        favoriteList.Select(p => Task.Run(async () =>
                            new PoetryFavorite {
                                Poetry =
                                    await poetryStorage.GetPeotryAsync(
                                        p.PoetryId),
                                Favorite = p
                            })))).ToList());
                    Loading = false;
                }));

        private RelayCommand _pageAppearingCommand;

        public RelayCommand<PoetryFavorite> PoetryTappedCommand =>
            _poetryTappedCommand ?? (_poetryTappedCommand =
                new RelayCommand<PoetryFavorite>(async poetryFavorite =>
                    await contentNavigationService.NavigateToAsync(
                        ContentNavigationServiceConstants.DetailPage,
                        poetryFavorite.Poetry)));

        private RelayCommand<PoetryFavorite> _poetryTappedCommand;

        /******** 私有变量 ********/

        private bool pageLoaded;
        private readonly object pageLoadedLock = new object();

        /******** 私有方法 ********/

        private async void FavoriteStorageOnUpdated(object sender,
            FavoriteStorageUpdatedEventArgs e) {
            var deferral = e.GetDeferral();

            var favorite = e.UpdatedFavorite;
            PoetryFavorites.Remove(PoetryFavorites.FirstOrDefault(p =>
                p.Favorite.PoetryId == favorite.PoetryId));

            if (favorite.IsFavorite) {
                var poetryFavorite = new PoetryFavorite {
                    Poetry =
                        await poetryStorage.GetPeotryAsync(favorite.PoetryId),
                    Favorite = favorite
                };

                var index = PoetryFavorites.IndexOf(
                    PoetryFavorites.FirstOrDefault(p =>
                        p.Favorite.Timestamp < favorite.Timestamp));
                if (index < 0) {
                    index = PoetryFavorites.Count;
                }

                PoetryFavorites.Insert(index, poetryFavorite);
            }

            deferral.Complete();
        }
    }

    public class PoetryFavorite {
        public Poetry Poetry { get; set; }
        public Favorite Favorite { get; set; }
    }
}